from typing import Iterable

from PySide6.QtCore import Qt, Signal
from PySide6.QtGui import QIntValidator
from PySide6.QtWidgets import (
    QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QListWidget, QLineEdit,
    QListWidgetItem
)

from common.equipment.reference import Equipment
from common.player.reference import Player
from common.resources import Resource
from gui.reference import SIZE_WIDTH, SIZE_HEIGHT
from gui.signals import SIGNALS
from utils.event_bus import EVENT_BUS
from utils.reference import message_box_information

_R = 0.7


class LineWidget(QWidget):
    buy_basket_changed = Signal(object, int)
    sell_basket_changed = Signal(object, int)

    def __init__(self, obj, num=0, is_buy=True):
        super().__init__()

        self.setFixedHeight(30)
        self.obj = obj
        self.num = num
        self.is_buy = is_buy

        width = self.width()

        layout = QHBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)

        if obj is None:
            price_label = QLabel('价格')
            price_label.setFixedWidth(int(width * 0.1))

            num_label = QLabel('数量')
            num_label.setFixedWidth(int(width * 0.2))

            space = QLabel('')
            space.setFixedWidth(80)

            name_label = QLabel('名称')
            name_label.setFixedWidth(width - price_label.width() - num_label.width() - 80)

            layout.addWidget(name_label)
            layout.addWidget(price_label)
            layout.addWidget(num_label)
            layout.addWidget(space)
        else:
            self.line_edit = QLineEdit()
            self.line_edit.setFixedWidth(50)
            self.btn = QPushButton('>>', self)
            self.btn.setFixedWidth(30)

            price_label = QLabel(f'{int(obj.price * (1 if is_buy else _R))}')
            price_label.setFixedWidth(int(width * 0.1))

            num_label = QLabel(f"{num if not is_buy else '∞'}")
            num_label.setFixedWidth(int(width * 0.2))
            self.num_label = num_label  # 保存引用以便更新

            name_label = QLabel(obj.name)
            name_label.setFixedWidth(width - price_label.width() - num_label.width() - 80)

            layout.addWidget(name_label)
            layout.addWidget(price_label)
            layout.addWidget(num_label)
            layout.addWidget(self.line_edit)
            layout.addWidget(self.btn)

            self.line_edit.setValidator(QIntValidator(0, 1000000))
            self.btn.clicked.connect(self.btn_click)
            self.line_edit.textChanged.connect(self.line_edit_change)

    def get_number(self, num=None):
        if num is None:
            text = self.line_edit.text()
        else:
            text = num

        if not text:
            return 0
        else:
            return int(text.strip())

    def btn_click(self):
        if self.is_buy:
            num = self.get_number() + 10
        else:
            num = self.num

        self.line_edit.setText(str(num))

    def line_edit_change(self, text):
        num = self.get_number(text)
        if not self.is_buy:
            self.btn.setEnabled(num != self.num)

        if self.is_buy:
            self.buy_basket_changed.emit(self.obj, num)
        else:
            self.sell_basket_changed.emit(self.obj, num)


class NpcShopWidget(QWidget):

    def __init__(self, title: str, player: Player, shop_type: str, shop_items: Iterable):
        super().__init__()

        self.player = player
        self.shop_type = shop_type
        self.shop_items = shop_items

        self.setWindowTitle(title)
        self.setGeometry(200, 200, SIZE_WIDTH, SIZE_HEIGHT)

        root_layout = QVBoxLayout(self)
        root_layout.setContentsMargins(0, 0, 0, 0)
        root_layout.setSpacing(0)

        self.display_label = QLabel(self)
        self.coin = player.bag.coin
        self.display_label.setText(f'<span style="font-size:20px">可用余额:</span> '
                                   f'<span style="color:blue;font-size:25px">{self.coin}</span>')

        btn_group_layout = QHBoxLayout()
        btn_group_layout.addWidget(self.display_label)

        self.btn_submit = QPushButton('成交')
        btn_group_layout.addWidget(self.btn_submit)
        self.btn_submit.clicked.connect(self.buy_commit)

        root_layout.addLayout(btn_group_layout)

        body_layout = QHBoxLayout()
        self.sell_widget = QListWidget(self)
        self.buy_widget = QListWidget(self)

        self.sell_widget.setStyleSheet('QListWidget::item{height:30px}')
        self.sell_widget.setSelectionMode(QListWidget.SelectionMode.NoSelection)
        self.buy_widget.setStyleSheet('QListWidget::item{height:30px}')
        self.buy_widget.setSelectionMode(QListWidget.SelectionMode.NoSelection)

        body_layout.addWidget(self.sell_widget)
        body_layout.addWidget(self.buy_widget)

        root_layout.addLayout(body_layout)
        self.buy_basket = dict()
        self.sell_basket = dict()

        self.setup_buy_lines()
        self.setup_sell_lines()

    def setup_buy_lines(self):
        self.buy_widget.clear()
        __item = QListWidgetItem()
        self.buy_widget.addItem(__item)
        self.buy_widget.setItemWidget(__item, LineWidget(None))

        for shop_item in self.shop_items:
            item = QListWidgetItem()
            item.setData(Qt.ItemDataRole.UserRole, shop_item)
            self.buy_widget.addItem(item)
            line = LineWidget(shop_item)
            line.buy_basket_changed.connect(self.buy_basket_change)
            self.buy_widget.setItemWidget(item, line)

    def setup_sell_lines(self):
        self.sell_widget.clear()
        __item = QListWidgetItem()
        self.sell_widget.addItem(__item)
        self.sell_widget.setItemWidget(__item, LineWidget(None))

        # 修复：重新获取背包中的实际数据
        for r, q in self.player.bag.iter():
            if q <= 0:
                continue

            item = QListWidgetItem()
            item.setData(Qt.ItemDataRole.UserRole, r)
            self.sell_widget.addItem(item)
            line = LineWidget(r, num=q, is_buy=False)
            line.sell_basket_changed.connect(self.sell_basket_change)
            self.sell_widget.setItemWidget(item, line)

    def buy_basket_change(self, obj, num):
        self.coin -= obj.price * (num - self.buy_basket.get(obj.key, 0))
        self.buy_basket[obj.key] = num
        self.update_data()

    def sell_basket_change(self, obj, num):
        old_num = self.sell_basket.get(obj.key, (obj, 0))[1]
        self.coin += int(obj.price * (num - old_num) * _R)
        self.sell_basket[obj.key] = obj, num
        self.update_data()

    def update_data(self, change_sell=False, change_buy=False):
        color = 'blue' if self.coin >= 0 else 'red'
        self.display_label.setText(f'<span style="font-size:20px">可用余额:</span> '
                                   f'<span style="color:{color};font-size:25px">{self.coin}</span>')

        if change_sell:
            self.setup_sell_lines()
        if change_buy:
            self.setup_buy_lines()

    def buy_commit(self):
        if self.coin < 0:
            message_box_information('可用余额不足')
            return

        if not self.sell_basket and not self.buy_basket:
            return

        # 处理购买
        data = [(1, self.shop_type, key, num) for key, num in self.buy_basket.items() if num != 0]

        # 处理卖出
        for obj, num in self.sell_basket.values():
            if num == 0:
                continue

            if isinstance(obj, Resource):
                data.append((0, 'material', obj.key, num))
            elif isinstance(obj, Equipment):
                data.append((0, 'equipment', obj, 1))

        if self.player.bag.update(data):
            self.player.bag.coin = self.coin
            # 更新首页面板的金币数量
            SIGNALS.update_player_penal.emit()
            # 给接受的任务发信号
            EVENT_BUS.player_interaction.emit(self.player)
        else:
            message_box_information('背包容量不足5')

        self.buy_basket.clear()
        self.sell_basket.clear()
        self.update_data(change_sell=True, change_buy=True)
